package com.vca.service.service.Impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vca.common.constants.*;
import com.vca.common.exception.VcaException;
import com.vca.common.model.course.CourseScheduling;
import com.vca.common.model.exceptions.ThirdPartyExceptions;
import com.vca.common.model.exhibition.ExhibitionScheduling;
import com.vca.common.model.invoice.InvoiceOrderRelation;
import com.vca.common.model.order.StoreOrder;
import com.vca.common.model.order.StoreOrderInfo;
import com.vca.common.model.order.StoreOrderStatus;
import com.vca.common.model.talk.TalkScheduling;
import com.vca.common.model.user.User;
import com.vca.common.model.user.UserCard;
import com.vca.common.model.user.UserToken;
import com.vca.common.model.vca_product.VcaProduct;
import com.vca.common.model.vca_product.VcaProductAttrValue;
import com.vca.common.model.wechat.WechatPayInfo;
import com.vca.common.response.OrderPayResultResponse;
import com.vca.common.response.UmsQueryResponse;
import com.vca.common.utils.DateUtil;
import com.vca.common.utils.RedisUtil;
import com.vca.common.utils.RestTemplateUtil;
import com.vca.common.utils.VcaUtil;
import com.vca.common.vo.*;
import com.vca.service.service.*;
import com.vca.service.util.UmsUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UmsPayServiceImpl implements UmsPayService {

    public static final Logger logger = LoggerFactory.getLogger(UmsPayServiceImpl.class);

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private StoreOrderService orderService;

    @Autowired
    private StoreOrderInfoService orderInfoService;

    @Autowired
    private WechatPayInfoService payInfoService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserTokenService userTokenService;

    @Autowired
    private UserCardService userCardService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private UmsUtils umsUtils;

    @Autowired
    private StoreOrderStatusService storeOrderStatusService;

    @Autowired
    private VcaProductService vcaProductService;

    @Autowired
    private VcaProductAttrValueService vcaProductAttrValueService;

    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Autowired
    private CourseSchedulingService courseSchedulingService;

    @Autowired
    private TalkSchedulingService talkSchedulingService;

    @Autowired
    private ExhibitionSchedulingService exhibitionSchedulingService;

    @Autowired
    private InvoiceOrderRelationService invoiceOrderRelationService;

    @Autowired
    private ThirdPartyExceptionsService thirdPartyExceptionsService;

    /**
     * @Description: 获取银联商务 全民付 配置
     * @Author: Li
     * @Date: 2022/10/27 11:14
     */
    @Override
    public Map<String, String> getUmsPayConfig() {
        return systemConfigService.info(68);
    }


    /**
     * @param orderNos 主订单号
     * @param ip       下单地址
     * @Description: 银联商务 全民付 下单
     * @Author: Li
     * @Date: 2022/10/20 14:44
     */

    @Override
    public OrderPayResultResponse payment(String language,List<String> orderNos, String ip) throws Exception {
        User info = userService.getInfo();
        List<StoreOrder> orders = orderService.list(new LambdaQueryWrapper<StoreOrder>().in(StoreOrder::getOrderId, orderNos).eq(StoreOrder::getUid, info.getUid()));
        if (orders.size() <= 0) {

            throw new VcaException("en".equals(language) ? "The current orderNo does not belong to the current user" : "当前orderNo不属于当前用户");
        }
        List<BigDecimal> payPrice = new ArrayList<BigDecimal>();
        if (ObjectUtil.isEmpty(orders)) {
            throw new VcaException("en".equals(language) ? "The order does not exist" : "该订单不存在");
        }
        orders.forEach(e -> {
            if (e.getIsDel()) {
                throw new VcaException("en".equals(language) ? "The order has been deleted" : "订单已被删除");
            }
            if (e.getPaid()) {
                throw new VcaException("en".equals(language) ? "Order paid" : "订单已支付");
            }
            payPrice.add(e.getPayPrice());
        });
        //前端响应对象
        OrderPayResultResponse response = new OrderPayResultResponse();
        //订单id
        response.setOrderNos(orderNos);
        WxPayJsResultVo vo = new WxPayJsResultVo();
        BigDecimal totalAmount = payPrice.stream().reduce(BigDecimal.ZERO, (p, q) -> p.add(q)).multiply(new BigDecimal("100"));
        if (totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
            response.setPaymentRequire(false);
            return response;
        }
        User user = userService.getInfo();
        if (ObjectUtil.isNull(user)) {
            throw new VcaException("用户不存在");
        }
        //获取用户openId
        UserToken userToken = userTokenService.getTokenByUserId(user.getUid(), 2);

        //获取 银联全民付 预下单信息
        Map<String, Object> unifiedorder = unifiedorder(orders, userToken.getToken());
        //交易类型
        response.setPayType(orders.get(0).getPayType());
        response.setPaymentRequire(true);
        //支付状态
        response.setStatus(true);
        Map<String, String> map = new HashMap<>();
        //银联全民付 订单号
        map.put("merOrderId", unifiedorder.get("merOrderId").toString());

        String appId = unifiedorder.get("appId").toString();
        String nonceStr = unifiedorder.get("nonceStr").toString();
        String sign = unifiedorder.get("paySign").toString();
        String prepayId = unifiedorder.get("package").toString();
        //添加微信订单记录
        WechatPayInfo payInfo = new WechatPayInfo();
        payInfo.setAppId(appId);
        payInfo.setNonceStr(nonceStr);
        payInfo.setDeviceInfo("MINI");
        payInfo.setOpenId(userToken.getToken());
        payInfo.setSign(sign);
        payInfo.setSignType(PayConstants.WX_PAY_SIGN_TYPE_MD5);
        payInfo.setBody("VCA");
        AttachVo attachVo = new AttachVo(Constants.SERVICE_PAY_TYPE_ORDER, user.getUid());
        payInfo.setAttach(JSON.toJSONString(attachVo));
        payInfo.setSpbillCreateIp(ip);
        payInfo.setTradeType(PayConstants.WX_PAY_TRADE_TYPE_JS);
        BigDecimal reduce = payPrice.stream().reduce(BigDecimal.ZERO, (p, q) -> p.add(q));
        payInfo.setTotalFee(reduce.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
        CreateOrderH5SceneInfoVo createOrderH5SceneInfoVo = new CreateOrderH5SceneInfoVo(
                new CreateOrderH5SceneInfoDetailVo(
                        systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_SITE_URL),
                        systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_SITE_NAME)
                )
        );
        payInfo.setSceneInfo(JSON.toJSONString(createOrderH5SceneInfoVo));
        payInfo.setPrepayId(prepayId);
        payInfo.setErrCode(unifiedorder.get("errCode").toString());
        payInfo.setTradeState(unifiedorder.get("targetStatus").toString());
        payInfo.setOpenId(userToken.getToken());
        payInfo.setOutTradeNo(unifiedorder.get("merOrderId").toString());

        Boolean execute = transactionTemplate.execute(e -> {
            return payInfoService.save(payInfo);
        });
        if (!execute) {
            throw new VcaException("en".equals(language) ? "Order placement failed" : "下单失败");
        }
        //
        //下列所有参数均由 银联全民付 返回
        //微信appId
        vo.setAppId(appId);
        //微信支付所需要的 随机字符
        vo.setNonceStr(nonceStr);
        // 预支付会话标识
        vo.setPackages(unifiedorder.get("package").toString());
        //签名类型
        vo.setSignType(unifiedorder.get("signType").toString());
        // 时间戳
        vo.setTimeStamp(unifiedorder.get("timeStamp").toString());
        //签名
        vo.setPaySign(sign);
        //预支付回话标识，用于后续接口调用中使用，该值有效期为2小时
        vo.setPartnerid("");
        response.setJsConfig(vo);
        return response;
    }


    /**
     * @param orderNos 主订单号
     * @Description: 银联商务 全民付 查看订单状态
     * @Author: Li
     * @Date: 2022/10/28 10:32
     */
    @Override
    public UmsQueryResponse queryPayStatus(String language,List<String> orderNos) throws Exception {
        User info = userService.getInfo();
        //根据订单号查询订单
        List<StoreOrder> orders = orderService.list(new LambdaQueryWrapper<StoreOrder>().in(StoreOrder::getOrderId, orderNos).eq(StoreOrder::getUid, info.getUid()));
        //判断是否存在订单
        if (ObjectUtil.isEmpty(orders)) {
            if("en".equals(language)){
                throw new VcaException("No Matching Order Found");
            }else{
                throw new VcaException("未找到相对应的订单");
            }
        }
        List<BigDecimal> payPrice = orders.stream().map(StoreOrder::getPayPrice).collect(Collectors.toList());

        UmsQueryResponse umsQueryResponse = new UmsQueryResponse(Boolean.TRUE, "en".equals(language) ? "Payment Completed" : "支付完成");
        BigDecimal totalAmount = payPrice.stream().reduce(BigDecimal.ZERO, (p, q) -> p.add(q));
        //判断支付状态
        List<StoreOrderInfo> orderInfos = new ArrayList<>();
        List<UserCard> userCards = new ArrayList<>();
        List<StoreOrderStatus> storeOrderStatuses = new ArrayList<>();
        if (totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
            umsQueryResponse.setStatus(true);
            orders.forEach(e -> {
                e.setTargetOrderId(null);
                //判断订单状态是否未支付 如果未支付 修改状态
                e.setPaid(true);
                //修改订单支付时间
                e.setPayTime(new Date());
                if (e.getType() == 4) {
                    List<StoreOrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, e.getOrderId()));
                    for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                        if (Objects.equals(vcaProductService.getById(storeOrderInfo.getProductId()).getCid(), Constants.CATEGORY_ID_OF_GIFT_CARD_TYPE)) {
                            storeOrderInfo.setStatus(3);
                            e.setStatus(3);
                            for (Integer i = 0; i < storeOrderInfo.getPayNum(); i++) {
                                UserCard userCard = getCard(storeOrderInfo, e.getUid());
                                userCards.add(userCard);
                            }
                            String giftCardAfterSalesTime = systemConfigService.getValueByKey(Constants.GIFT_CARD_AFTER_SALES_TIME);
                            e.setClosingTime(new Date());
                            DateTime dateTime = cn.hutool.core.date.DateUtil.offset(e.getClosingTime(), DateField.DAY_OF_YEAR, Integer.parseInt(giftCardAfterSalesTime) + 1);
                            Calendar calendar = Calendar.getInstance();
                            calendar.setTime(dateTime);
                            calendar.set(Calendar.HOUR_OF_DAY, 0);
                            calendar.set(Calendar.MINUTE, 0);
                            calendar.set(Calendar.SECOND, 0);
                            calendar.set(Calendar.MILLISECOND, 0);
                            e.setAfterSalesDeadline(calendar.getTime());
                        }
                        orderInfos.add(storeOrderInfo);
                        StoreOrderStatus storeOrderStatus = new StoreOrderStatus();
                        storeOrderStatus.setOid(e.getId());
                        storeOrderStatus.setChangeType(Constants.ORDER_LOG_PAY_SUCCESS);

                        storeOrderStatus.setChangeMessage("en".equals(language) ? "Payment Successful" : "支付成功");
                        storeOrderStatus.setCreateTime(DateUtil.nowDateTime());
                        storeOrderStatuses.add(storeOrderStatus);
                    }
                }
                if (e.getType() != 4) {
                    List<StoreOrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, e.getOrderId()));
                    StoreOrderStatus storeOrderStatus = new StoreOrderStatus();
                    storeOrderStatus.setOid(e.getId());
                    storeOrderStatus.setChangeType(Constants.ORDER_LOG_PAY_SUCCESS);

                    storeOrderStatus.setChangeMessage("en".equals(language) ? "Payment Successful" : "支付成功");
                    storeOrderStatus.setCreateTime(DateUtil.nowDateTime());
                    storeOrderStatuses.add(storeOrderStatus);
                    for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                        storeOrderInfo.setStatus(1);
                        e.setStatus(1);
                        if (Objects.equals(storeOrderInfo.getBuyer(), storeOrderInfo.getLecturer())) {
                            storeOrderInfo.setIsGet(true);
                        }
                        orderInfos.add(storeOrderInfo);
                    }
                }
                e.setPayType("weixin");
            });
            //订单支付完成
            umsQueryResponse.setStatus(Boolean.TRUE);

            umsQueryResponse.setMsg("en".equals(language) ? "Payment Successful" : "支付成功");
            umsQueryResponse.setPayFree(BigDecimal.ZERO);
            //事务
            Boolean execute = transactionTemplate.execute(e -> {
                orderService.updateBatchById(orders);
                orderInfoService.updateBatchById(orderInfos);
                // TODO: 2022/12/28 处理外部预约人数
                handlerAppoinent(orderInfos);
                userCardService.saveBatch(userCards);
                storeOrderStatusService.saveBatch(storeOrderStatuses);
                return Boolean.TRUE;
            });
            if (!execute) {
                if("en".equals(language)){
                    throw new VcaException("Order Inquiry Failed");
                }else{
                    throw new VcaException("查询订单失败");
                }
            }
            orders.forEach(o -> {
                redisUtil.lPush(OrderRedisConstans.ORDER_PAY_SUCCESSFUL, o.getOrderId());
                redisUtil.lPush(OrderRedisConstans.ACTIVITY_START_KEY, o.getOrderId());
            });
            return umsQueryResponse;
        }
        orders.forEach(e -> {
            //判断是否为正常下单流程的订单
            if (ObjectUtil.isEmpty(e.getUmsMerOrderId())) {
                if("en".equals(language)){
                    throw new VcaException("Invalid Order");
                }else{
                    throw new VcaException("订单非法");
                }
            }
        });
        //获取 银联全民付 配置信息
        Map<String, String> umsPayConfig = getUmsPayConfig();
        //当前日期 格式为 yyyyMMddHHmmss
        //获取当前时间
        String timestamp = DateUtil.nowDateTime(Constants.DATE_TIME_FORMAT_NUM);

        //1. 组建请求报文
        UmsPayVo umsPayVo = new UmsPayVo();
        //报文请求时间
        umsPayVo.setRequestTimestamp(timestamp);
        //商户号
        umsPayVo.setMid(umsPayConfig.get(UmsPayConstants.UMS_PAY_MID));
        //终端号
        umsPayVo.setTid(umsPayConfig.get(UmsPayConstants.UMS_PAY_TID));
        //机构商户号
        umsPayVo.setInstMid(UmsPayConstants.UMS_PAY_INSTMID_QRPAYDEFAULT);
        //商户订单号
        umsPayVo.setMerOrderId(orders.get(0).getUmsMerOrderId());

        umsPayVo.setTradeType(UmsPayConstants.UMS_PAY_TRADETYPE_MINI);

        //2. 获取认证报文
        String authorization = umsUtils.getAccessToken();

        //3.拼接请求链接
        String url = UmsPayUrlConstants.UMS_PAY_DEV_URL;
        url = url + UmsPayUrlConstants.UMS_PAY_QUERY_URL;
        //传递 accessToken 到请求头
        Map<String, String> headers = new HashMap();

        headers.put(UmsPayConstants.UMS_PAY_HEADER, authorization);
        //4. 发送http请求，并解析返回信息
        String jsonData = restTemplateUtil.postMapData(url, JSON.parseObject(JSON.toJSONString(umsPayVo)), headers);
        JSONObject jsonObject = JSON.parseObject(jsonData);
        log.info("jsonObject-------------------------------->{}", jsonObject);
        //从返回信息中获取,获取订单状态
        String status = jsonObject.getString("status");
        //从返回信息中获取,获取下单时间
        String payTime = jsonObject.getString("payTime");
        ////从返回信息中获取,获取支付方式
        String targetSys = jsonObject.getString("targetSys");
        //支付金额
        String totalAmount1 = jsonObject.getString("totalAmount");
        if (ObjectUtil.isEmpty(totalAmount1)) {
            totalAmount1 = "0";
        }
        totalAmount1 = new BigDecimal(totalAmount1).divide(new BigDecimal("100")).setScale(2, RoundingMode.UP).toString();
        switch (status) {
            //交易创建，等待买家付款。
            case UmsPayConstants.UMS_PAY_STATUS_WAIT_BUYER_PAY:
                //修改订单的支付状态
                orders.forEach(e -> {
                    e.setPaid(false);
                });
                //订单未支付
                umsQueryResponse.setStatus(Boolean.TRUE);
                umsQueryResponse.setPayFree(new BigDecimal(totalAmount1));
                //原因
                umsQueryResponse.setMsg("en".equals(language) ? "Order Pending Payment" : "订单待支付");
                break;
            //交易成功
            case UmsPayConstants.UMS_PAY_STATUS_TRADE_SUCCESS:
                //判断是否添加过第三方订单号 未添加 则添加上
                String targetOrderId = jsonObject.getString("targetOrderId");
                orders.forEach(e -> {
                    //修改订单支付时间
                    e.setPayTime(DateUtil.strToDate(payTime, Constants.DATE_FORMAT));
                    if (e.getType() == 4) {
                        List<StoreOrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, e.getOrderId()));
                        for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                            if (Objects.equals(vcaProductService.getById(storeOrderInfo.getProductId()).getCid(), Constants.CATEGORY_ID_OF_GIFT_CARD_TYPE)) {
                                storeOrderInfo.setStatus(3);
                                e.setStatus(3);
                                for (Integer i = 0; i < storeOrderInfo.getPayNum(); i++) {
                                    UserCard userCard = getCard(storeOrderInfo, e.getUid());
                                    userCards.add(userCard);
                                }
                                String giftCardAfterSalesTime = systemConfigService.getValueByKey(Constants.GIFT_CARD_AFTER_SALES_TIME);
                                e.setClosingTime(new Date());
                                DateTime dateTime = cn.hutool.core.date.DateUtil.offset(e.getClosingTime(), DateField.DAY_OF_YEAR, Integer.parseInt(giftCardAfterSalesTime) + 1);
                                Calendar calendar = Calendar.getInstance();
                                calendar.setTime(dateTime);
                                calendar.set(Calendar.HOUR_OF_DAY, 0);
                                calendar.set(Calendar.MINUTE, 0);
                                calendar.set(Calendar.SECOND, 0);
                                calendar.set(Calendar.MILLISECOND, 0);
                                e.setAfterSalesDeadline(calendar.getTime());
                            }
                            orderInfos.add(storeOrderInfo);
                            StoreOrderStatus storeOrderStatus = new StoreOrderStatus();
                            storeOrderStatus.setOid(e.getId());
                            storeOrderStatus.setChangeType(Constants.ORDER_LOG_PAY_SUCCESS);

                            storeOrderStatus.setChangeMessage("en".equals(language) ? "Payment Successful" : "支付成功");
                            storeOrderStatus.setCreateTime(DateUtil.nowDateTime());
                            storeOrderStatuses.add(storeOrderStatus);
                        }
                    }
                    if (e.getType() != 4) {
                        List<StoreOrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, e.getOrderId()));
                        logger.info("orderInfoList---->{}", orderInfoList);
                        StoreOrderStatus storeOrderStatus = new StoreOrderStatus();
                        storeOrderStatus.setOid(e.getId());
                        storeOrderStatus.setChangeType(Constants.ORDER_LOG_PAY_SUCCESS);

                        storeOrderStatus.setChangeMessage("en".equals(language) ? "Payment Successful" : "支付成功");
                        storeOrderStatus.setCreateTime(DateUtil.nowDateTime());
                        storeOrderStatuses.add(storeOrderStatus);
                        for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                            storeOrderInfo.setStatus(1);
                            e.setStatus(1);
                            if (Objects.equals(storeOrderInfo.getBuyer(), storeOrderInfo.getLecturer())) {
                                storeOrderInfo.setIsGet(true);
                            }
                            orderInfos.add(storeOrderInfo);
                        }
                        e.setStatus(1);
                    }
                    e.setTargetOrderId(targetOrderId);
                    //判断订单状态是否未支付 如果未支付 修改状态
                    e.setPaid(true);
                    //订单支付方式
                    if (targetSys.equals("WXPay")) {
                        e.setPayType("weixin");
                    }
                });
                //订单支付完成
                umsQueryResponse.setStatus(Boolean.TRUE);
                umsQueryResponse.setPayFree(new BigDecimal(totalAmount1));
                umsQueryResponse.setMsg("en".equals(language) ? "Payment Completed" : "支付完成");
                break;
            //超时未支付 或 交易失败
            case UmsPayConstants.UMS_PAY_STATUS_TRADE_CLOSED:
                //订单未支付
                umsQueryResponse.setStatus(Boolean.FALSE);
                umsQueryResponse.setPayFree(new BigDecimal(totalAmount1));
                //原因
                umsQueryResponse.setMsg("en".equals(language) ? "Order Payment Timeout" : "订单支付超时");
                break;
            default:
                break;
        }
        //事务
        Boolean execute = transactionTemplate.execute(e -> {
            logger.info("orderInfos.size()==>{}", orderInfos.size());
            if (orderInfos.size() > 0) {
                orderInfoService.updateBatchById(orderInfos);
                logger.info("orderInfos==>{}", orderInfos);
            }
            if (orders.size() > 0) {
                orderService.updateBatchById(orders);
                logger.info("orders----->{}", orders);
            }
            if (status.equals(UmsPayConstants.UMS_PAY_STATUS_TRADE_SUCCESS)) {
                // TODO: 2022/12/28 处理外部预约人数
                handlerAppoinent(orderInfos);
            }
            userCardService.saveBatch(userCards);
            storeOrderStatusService.saveBatch(storeOrderStatuses);
            return Boolean.TRUE;
        });
        if (!execute) {
            if("en".equals(language)){
                throw new VcaException("Order Inquiry Failed");
            }else{
                throw new VcaException("查询订单失败");
            }
        }
        return umsQueryResponse;
    }

    /**
     * @Description:处理外部预约人数或商品销量
     * @author:chenbing
     * @date 2022/12/28 9:37
     */
    private void handlerAppoinent(List<StoreOrderInfo> orderInfos) {
        List<CourseScheduling> courseSchedulings = new ArrayList<>();
        List<TalkScheduling> talkSchedulings = new ArrayList<>();
        List<ExhibitionScheduling> exhibitionSchedulings = new ArrayList<>();
        List<VcaProduct> vcaProducts = new ArrayList<>();
        List<VcaProductAttrValue> vcaProductAttrValues = new ArrayList<>();
        for (StoreOrderInfo orderInfo : orderInfos) {
            switch (orderInfo.getType()) {
                case 0:
                case 1:
                    //todo 课程、套课
                    CourseScheduling courseScheduling = courseSchedulingService.getById(orderInfo.getSchedulingId());
                    courseScheduling.setExternalAppointment(courseScheduling.getExternalAppointment() + 1);
//                    courseSchedulings.add(courseScheduling);
                    break;
                case 2:
                    // TODO: 2022/12/28 讲座
                    TalkScheduling talkScheduling = talkSchedulingService.getById(orderInfo.getSchedulingId());
                    talkScheduling.setNumberOfAppointments(talkScheduling.getNumberOfAppointments() + 1);
//                    talkSchedulings.add(talkScheduling);
                    break;
                case 3:
                    // TODO: 2022/12/28 展览
                    ExhibitionScheduling exhibitionScheduling = exhibitionSchedulingService.getById(orderInfo.getSchedulingId());
                    exhibitionScheduling.setNumberOfAppointments(exhibitionScheduling.getNumberOfAppointments() + 1);
//                    exhibitionSchedulings.add(exhibitionScheduling);
                    break;
                case 4:
                    // TODO: 2022/12/28 商品
                    VcaProduct vcaProduct = vcaProductService.getById(orderInfo.getProductId());
                    vcaProduct.setSales(vcaProduct.getSales() + orderInfo.getPayNum());
                    VcaProductAttrValue productAttrValue = vcaProductAttrValueService.getById(orderInfo.getAttrValueId());
                    productAttrValue.setSales(vcaProduct.getSales() + orderInfo.getPayNum());
                    vcaProducts.add(vcaProduct);
                    vcaProductAttrValues.add(productAttrValue);
                    break;
                default:
                    break;
            }
        }
        Boolean execute = transactionTemplate.execute(e -> {
            if (courseSchedulings.size() > 0) {
                courseSchedulingService.updateBatchById(courseSchedulings);
            }
            if (talkSchedulings.size() > 0) {
                talkSchedulingService.updateBatchById(talkSchedulings);
            }
            if (exhibitionSchedulings.size() > 0) {
                exhibitionSchedulingService.updateBatchById(exhibitionSchedulings);
            }
            if (vcaProducts.size() > 0) {
                vcaProductService.updateBatchById(vcaProducts);
            }
            if (vcaProductAttrValues.size() > 0) {
                vcaProductAttrValueService.updateBatchById(vcaProductAttrValues);
            }
            return Boolean.TRUE;
        });
        if (!execute) {
            throw new VcaException("新增预约人数失败");
        }
    }

    public UserCard getCard(StoreOrderInfo orderInfo, Integer uid) {
        UserCard userCard = new UserCard();
        userCard.setUid(uid);
        userCard.setCardId(orderInfo.getProductId());
        VcaProduct product = vcaProductService.getById(orderInfo.getProductId());
        userCard.setCardNo(RandomUtil.randomString(6) + System.currentTimeMillis());
//        if (StringUtils.isNotBlank(product.getCardNo())) {
//            userCard.setCardNo(product.getCardNo() + userCard.getCardNo());
//        }
        userCard.setOrderId(orderInfo.getMerOrderNo());
        userCard.setStutus(0);
        userCard.setName(orderInfo.getName());
        userCard.setNameEn(orderInfo.getNameEn());
        userCard.setMainColor(product.getMainColor());
        userCard.setSecondaryColor(product.getSecondaryColor());
        userCard.setTertiaryColor(product.getTertiaryColor());
        userCard.setIntroduction(product.getIntroduction());
        userCard.setFaceValue(product.getFaceValue());
        userCard.setStartTime(new Date());
        DateTime dateTime = cn.hutool.core.date.DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, product.getEndTime() + 1);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateTime);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date dayStart = calendar.getTime();
        userCard.setEndTime(dayStart);
        userCard.setIsDeleted(0);
        userCard.setType("online_buy");
        userCard.setUseType(product.getUseType());
        userCard.setPrimaryKey(product.getPrimaryKey());
        userCard.setUserAround(product.getUseAround());
        userCard.setCreateTime(new Date());
        userCard.setUpdateTime(new Date());
        return userCard;
    }

    /**
     * @param refundList 退款集合
     * @Description: 银联商务 全民付 退款
     * @Author: Li
     * @Date: 2022/10/28 11:02
     */
    @SneakyThrows
    @Override
    public Boolean refund(List<UmsPayRefundVo> refundList) {
        if (ObjectUtil.isEmpty(refundList)) {
            return Boolean.TRUE;
        }
        List<StoreOrderInfo> orderInfos = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().in(StoreOrderInfo::getMerOrderNo, refundList.stream().map(UmsPayRefundVo::getMerOrderNo).collect(Collectors.toList())));
        if (ObjectUtil.isEmpty(orderInfos)) {
            throw new VcaException("该订单不存在");
        }
        //查询是否存在订单
        List<String> orderNos = orderInfos.stream().map(StoreOrderInfo::getOrderNo).collect(Collectors.toList());
        List<StoreOrder> orders = orderService.list(new LambdaQueryWrapper<StoreOrder>().in(StoreOrder::getOrderId, orderNos));
        if (ObjectUtil.isEmpty(orders)) {
            throw new VcaException("该订单不存在");
        }
        orders.forEach(e -> {
            //判断订单是否为正常下单
            if (ObjectUtil.isEmpty(e.getUmsMerOrderId()) || ObjectUtil.isEmpty(e.getTargetOrderId()) || !e.getPaid()) {
                throw new VcaException("未交易订单请勿退款");
            }
        });
        //获取 银联全民付 配置信息
        Map<String, String> umsPayConfig = getUmsPayConfig();
        //当前日期 格式为 yyyyMMddHHmmss
        String timestamp = DateUtil.nowDateTime(Constants.DATE_TIME_FORMAT_NUM);

        //1. 组建请求报文
        UmsPayVo umsPayVo = new UmsPayVo();
        //报文请求时间
        umsPayVo.setRequestTimestamp(timestamp);
        //商户号
        umsPayVo.setMid(umsPayConfig.get(UmsPayConstants.UMS_PAY_MID));
        //终端号
        umsPayVo.setTid(umsPayConfig.get(UmsPayConstants.UMS_PAY_TID));
        //instMid
        umsPayVo.setInstMid(UmsPayConstants.UMS_PAY_INSTMID_YUEDANDEFAULT);
        //商户订单号
        umsPayVo.setMerOrderId(orders.get(0).getUmsMerOrderId());
        //支付订单号
        umsPayVo.setTargetOrderId(orders.get(0).getTargetOrderId());
        //退款金额
        umsPayVo.setRefundAmount(refundList.stream().map(UmsPayRefundVo::getAmount).collect(Collectors.toList()).stream().reduce(BigDecimal.ZERO, (p, q) -> p.add(q)).multiply(new BigDecimal("100")).intValue());
        umsPayVo.setTradeType(UmsPayConstants.UMS_PAY_TRADETYPE_MINI);
        //退款订单号
        umsPayVo.setRefundOrderId(umsPayConfig.get(UmsPayConstants.UMS_SOURCE_NO) + timestamp + VcaUtil.randomCount(1000000, 9999999));

        //2. 获取认证报文
        String authorization = umsUtils.getAccessToken();

        //3.拼接链接
        String url = UmsPayUrlConstants.UMS_PAY_DEV_URL;
        url = url + UmsPayUrlConstants.UMS_PAY_REFUND_URL;
        //传递 accessToken 到请求头
        Map<String, String> headers = new HashMap();
        headers.put(UmsPayConstants.UMS_PAY_HEADER, authorization);
        //4. 发送http请求，并解析返回信息
        log.info("------------退款开始-------------------->");
        String jsonData = restTemplateUtil.postMapData(url, JSON.parseObject(JSON.toJSONString(umsPayVo)), headers);
        JSONObject jsonObject = JSON.parseObject(jsonData);
        log.info("jsonObject-------------------------------->{}", jsonObject);
        String totalAmount = jsonObject.getString("totalAmount");
        //判断是否退款失败
        String errCode = jsonObject.getString("errCode");
        if (!errCode.equals(UmsPayConstants.UMS_PAY_ERRCODE_STATUS_SUCCESS)) {
            String errMsg = jsonObject.get("errMsg").toString();
            List<String> list = orders.stream().map(StoreOrder::getOrderId).collect(Collectors.toList());
            String err = "退款失败 " + errMsg + "订单号：" + list;
            transactionTemplate.execute(e -> {
                storeOrderStatusService.createLog(orders.get(0).getId(), "refundError", orders.get(0).getType().equals(4) ? 1 : 0, err);
                return Boolean.TRUE;
            });
            throw new VcaException(err);
        }
        String refundOrderId = jsonObject.getString("refundOrderId").toString();
        Map<String, List<UmsPayRefundVo>> listMap = refundList.stream().collect(Collectors.groupingBy(UmsPayRefundVo::getMerOrderNo));
        orderInfos.forEach(e -> {
            e.setUmsRefundOrderId(refundOrderId);
            //修改状态为 已退款
            e.setRefundStatus(3);
            //退款时间
            e.setRefundReasonTime(DateUtil.nowDateTime());
            //退款金额
            List<UmsPayRefundVo> umsPayRefundVos = listMap.get(e.getMerOrderNo());
            e.setRefundPrice(umsPayRefundVos.get(0).getAmount());
        });
        orders.forEach(e -> {
            e.setRefundStatus(3);
            e.setRefundReasonTime(DateUtil.nowDateTime());
            e.setRefundPrice(new BigDecimal(totalAmount).divide(new BigDecimal("100")).setScale(2, RoundingMode.UP));
        });
        log.info("------------退款结束-------------------->");
        return transactionTemplate.execute(e -> {
            orderService.updateBatchById(orders);
            return orderInfoService.updateBatchById(orderInfos);
        });

    }

    /**
     * @param merOrderNos orderInfo 子订单号
     * @Description: 银联商务 全民付 退款查询
     * @Author: Li
     * @Date: 2022/10/28 11:02
     */
    @Override
    public UmsQueryResponse refundQuery(List<String> merOrderNos) throws Exception {
        //查询订单是否存在
        List<StoreOrderInfo> orderInfos = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getMerOrderNo, merOrderNos));
        StoreOrder order = orderService.getByOrderId(orderInfos.get(0).getOrderNo());
        if (ObjectUtil.isEmpty(order)) {
            throw new VcaException("该订单不存在");
        }
        //判断订单是否为正常下单流程
        if (ObjectUtil.isEmpty(order.getUmsMerOrderId()) || ObjectUtil.isEmpty(order.getTargetOrderId()) || !order.getPaid()) {
            throw new VcaException("未交易订单请勿退款");
        }
        //判断订单是否被逻辑删除
        if (order.getIsDel()) {
            throw new VcaException("订单已被删除");
        }
        if (ObjectUtil.isEmpty(orderInfos)) {
            throw new VcaException("该订单不存在");
        }
        //获取 银联全民付 配置信息
        Map<String, String> umsPayConfig = getUmsPayConfig();
        //当前日期 格式为 yyyyMMddHHmmss
        String timestamp = DateUtil.nowDateTime(Constants.DATE_TIME_FORMAT_NUM);

        //1. 组建请求报文
        UmsPayVo umsPayVo = new UmsPayVo();
        //报文请求时间
        umsPayVo.setRequestTimestamp(timestamp);
        //商户号
        umsPayVo.setMid(umsPayConfig.get(UmsPayConstants.UMS_PAY_MID));
        //终端号
        umsPayVo.setTid(umsPayConfig.get(UmsPayConstants.UMS_PAY_TID));
        //机构商户号
        umsPayVo.setInstMid(UmsPayConstants.UMS_PAY_INSTMID_MINIDEFAULT);
        //商户订单号
        umsPayVo.setMerOrderId(orderInfos.get(0).getUmsRefundOrderId());
        umsPayVo.setTradeType(UmsPayConstants.UMS_PAY_TRADETYPE_MINI);

        //2. 获取认证报文
        String authorization = umsUtils.getAccessToken();

        //3.拼接支付链接
        String url = UmsPayUrlConstants.UMS_PAY_DEV_URL;
        url = url + UmsPayUrlConstants.UMS_PAY_REFUND_QUERY_URL;
        //传递 accessToken 到请求头
        Map<String, String> headers = new HashMap();
        headers.put(UmsPayConstants.UMS_PAY_HEADER, authorization);
        //4. 发送http请求，并解析返回信息
        String jsonData = restTemplateUtil.postMapData(url, JSON.parseObject(JSON.toJSONString(umsPayVo)), headers);
        JSONObject jsonObject = JSON.parseObject(jsonData);
        log.info("jsonObject-------------------------------->{}", jsonObject);
        //从返回信息中获取退款状态码
        String refundStatus = jsonObject.getString("refundStatus");
        //退款金额
        String sendBackAmount = jsonObject.getString("sendBackAmount");
        if (ObjectUtil.isEmpty(sendBackAmount)) {
            sendBackAmount = "0";
        }
        sendBackAmount = new BigDecimal(sendBackAmount).toString();
        //退款交易时间
        String payTime = jsonObject.getString("payTime");
        //退款金额
        String totalAmount = jsonObject.getString("totalAmount");
        UmsQueryResponse response = new UmsQueryResponse();
        //判断订单退款状态
        switch (refundStatus) {
            //退款处理中
            case UmsPayConstants.UMS_PAY_REFUND_STATUS_PROCESSING:
                orderInfos.forEach(e -> {
                    //判断订单的退款状态是否为 申请中 进行修改为退款中
                    e.setRefundStatus(3);
                });
                //返回前端原因
                response.setMsg("退款处理中");
                //返回前端 true
                response.setStatus(Boolean.TRUE);
                response.setPayFree(new BigDecimal(sendBackAmount));
                break;
            //退款成功
            case UmsPayConstants.UMS_PAY_REFUND_STATUS_SUCCESS:
                //判断订单退款状态是否为 申请中 或 退款中
                orderInfos.forEach(e -> {
                    //修改状态为 已退款
                    e.setRefundStatus(2);
                    //退款时间
                    e.setRefundReasonTime(DateUtil.nowDateTime());
                });
                order.setRefundStatus(2);
                //退款时间
                order.setRefundReasonTime(DateUtil.nowDateTime());
                //退款金额
                order.setRefundPrice(new BigDecimal(totalAmount));
                //返回前端原因
                response.setMsg("退款成功");
                //返回前端 true
                response.setStatus(Boolean.TRUE);
                response.setPayFree(new BigDecimal(sendBackAmount));
                break;
            //退款失败
            case UmsPayConstants.UMS_PAY_REFUND_STATUS_FAIL:
                //返回前端原因
                response.setMsg("退款失败");
                //返回前端 false
                response.setStatus(Boolean.FALSE);
                response.setPayFree(new BigDecimal(sendBackAmount));
                break;
            default:
                break;
        }
        //事务
        Boolean execute = transactionTemplate.execute(e -> {
            orderService.updateById(order);
            return orderInfoService.updateBatchById(orderInfos);
        });
        //判断是否修改成功
        if (!execute) {
            response.setMsg("退款失败");
            response.setStatus(Boolean.FALSE);
        }
        return response;
    }

    /**
     * @param orderNos
     * @Description 银联商务 全民付 订单关闭.
     * @author : Li
     * @date : 2022/10/28 11:02
     */
    @Override
    public Boolean close(List<String> orderNos) throws Exception {
        User info = userService.getInfo();
        //根据订单号查询订单
        List<StoreOrder> orders = orderService.list(new LambdaQueryWrapper<StoreOrder>().in(StoreOrder::getOrderId, orderNos).eq(StoreOrder::getUid, info.getUid()));
        //判断是否存在订单
        if (ObjectUtil.isEmpty(orders)) {
            throw new VcaException("未找到相对应的订单");
        }
        Map<String, String> umsPayConfig = getUmsPayConfig();
        //当前日期 格式为 yyyyMMddHHmmss
        String timestamp = DateUtil.nowDateTime(Constants.DATE_TIME_FORMAT_NUM);

        //1. 组建请求报文
        UmsPayVo umsPayVo = new UmsPayVo();
        umsPayVo.setRequestTimestamp(timestamp);
        umsPayVo.setMid(umsPayConfig.get(UmsPayConstants.UMS_PAY_MID));
        umsPayVo.setTid(umsPayConfig.get(UmsPayConstants.UMS_PAY_TID));
        umsPayVo.setInstMid(UmsPayConstants.UMS_PAY_INSTMID_MINIDEFAULT);
        umsPayVo.setMerOrderId(orders.get(0).getUmsMerOrderId());
        umsPayVo.setTradeType(UmsPayConstants.UMS_PAY_TRADETYPE_MINI);

        //2. 获取认证报文
        String authorization = umsUtils.getAccessToken();

        //3.拼接支付链接
        String url = UmsPayUrlConstants.UMS_PAY_DEV_URL;
        url = url + UmsPayUrlConstants.UMS_PAY_CLOSE_URL;
        Map<String, String> headers = new HashMap();
        headers.put(UmsPayConstants.UMS_PAY_HEADER, authorization);
        //4. 发送http请求，并解析返回信息
        String jsonData = restTemplateUtil.postMapData(url, JSON.parseObject(JSON.toJSONString(umsPayVo)), headers);
        JSONObject jsonObject = JSON.parseObject(jsonData);
        log.info("jsonObject-------------------------------->{}", jsonObject);
        String errCode = jsonObject.getString("errCode");
        if (!errCode.equals(UmsPayConstants.UMS_PAY_ERRCODE_STATUS_SUCCESS)) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * @param params
     * @Description: 银联商务 全民付 支付结果通知
     * @Author: Li
     * @Date: 2022/10/31 09:45
     */
    @Override
    public Boolean resultInform(Map<String, Object> params) {
        logger.info("===================支付结果回调开始======================");
        logger.info("params-->{}", JSON.toJSONString(params));
        String status = params.get("status").toString();
        String merOrderId = params.get("merOrderId").toString();
        String targetOrderId = params.get("targetOrderId").toString();
        String payTime = params.get("payTime").toString();
        List<StoreOrder> orders = new ArrayList<>();
        List<StoreOrder> orderList = orderService.getOrderByMerOrderIdAndTargetOrderId(merOrderId, targetOrderId);
        if (ObjectUtil.isEmpty(orderList)) {
            log.info("未找到银联 全民付 订单号---->{},所属的订单记录", merOrderId);
            return Boolean.FALSE;
        }
        WechatPayInfo payInfo = payInfoService.getByNo(merOrderId);
        if (ObjectUtil.isEmpty(payInfo)) {
            log.info("未找到银联 全民付 订单号---->{},所属的订单记录", merOrderId);
            return Boolean.FALSE;
        }
        List<StoreOrderInfo> orderInfos = new ArrayList<>();
        List<StoreOrderInfo> addOrderInfos = new ArrayList<>();
        List<Integer> ids = new ArrayList<>();
        List<UserCard> userCards = new ArrayList<>();
        List<UserCard> addUserCards = new ArrayList<>();
        UmsQueryResponse umsQueryResponse = new UmsQueryResponse();
        ThirdPartyExceptions thirdPartyExceptions = null;
        List<StoreOrderStatus> storeOrderStatuses = new ArrayList<>();
        switch (status) {
            //交易创建，等待买家付款。
            case UmsPayConstants.UMS_PAY_STATUS_WAIT_BUYER_PAY:
                orderList.forEach(e -> {
                    //修改订单的支付状态
                    e.setPaid(false);
                });
                //订单未支付
                umsQueryResponse.setStatus(Boolean.FALSE);
                //原因
                umsQueryResponse.setMsg("订单待支付");
                break;
            //超时未支付 或 交易失败
            case UmsPayConstants.UMS_PAY_STATUS_TRADE_CLOSED:
                //订单未支付
                umsQueryResponse.setStatus(Boolean.FALSE);
                //原因
                umsQueryResponse.setMsg("订单支付超时");
                logger.info("订单------->{},支付超时", orderList.get(0).getUmsMerOrderId());
                break;
            //交易成功 支付完成
            case UmsPayConstants.UMS_PAY_STATUS_TRADE_SUCCESS:
                //判断是否添加过第三方订单号 未添加 则添加上
                for (StoreOrder e : orderList) {
                    if (e.getPaid()) {
                        continue;
                    }
                    //修改订单支付时间
                    e.setPayTime(DateUtil.strToDate(payTime, Constants.DATE_FORMAT));
                    if (e.getType() == 4) {
                        List<StoreOrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, e.getOrderId()));
                        for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                            if (Objects.equals(vcaProductService.getById(storeOrderInfo.getProductId()).getCid(), Constants.CATEGORY_ID_OF_GIFT_CARD_TYPE)) {
                                storeOrderInfo.setStatus(3);
                                e.setStatus(3);
                                for (Integer i = 0; i < storeOrderInfo.getPayNum(); i++) {
                                    UserCard userCard = getCard(storeOrderInfo, e.getUid());
                                    addUserCards.add(userCard);
                                }
                                String giftCardAfterSalesTime = systemConfigService.getValueByKey(Constants.GIFT_CARD_AFTER_SALES_TIME);
                                e.setClosingTime(new Date());
                                DateTime dateTime = cn.hutool.core.date.DateUtil.offset(e.getClosingTime(), DateField.DAY_OF_YEAR, Integer.parseInt(giftCardAfterSalesTime) + 1);
                                Calendar calendar = Calendar.getInstance();
                                calendar.setTime(dateTime);
                                calendar.set(Calendar.HOUR_OF_DAY, 0);
                                calendar.set(Calendar.MINUTE, 0);
                                calendar.set(Calendar.SECOND, 0);
                                calendar.set(Calendar.MILLISECOND, 0);
                                e.setAfterSalesDeadline(calendar.getTime());
                            }
                            addOrderInfos.add(storeOrderInfo);
                            StoreOrderStatus storeOrderStatus = new StoreOrderStatus();
                            storeOrderStatus.setOid(e.getId());
                            storeOrderStatus.setChangeType(Constants.ORDER_LOG_PAY_SUCCESS);
                            storeOrderStatus.setChangeMessage("支付成功");
                            storeOrderStatus.setCreateTime(DateUtil.nowDateTime());
                            storeOrderStatuses.add(storeOrderStatus);
                        }
                    }
                    if (e.getType() != 4) {
                        List<StoreOrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, e.getOrderId()));
                        logger.info("orderInfoList---->{}", orderInfoList);
                        StoreOrderStatus storeOrderStatus = new StoreOrderStatus();
                        storeOrderStatus.setOid(e.getId());
                        storeOrderStatus.setChangeType(Constants.ORDER_LOG_PAY_SUCCESS);
                        storeOrderStatus.setChangeMessage("支付成功");
                        storeOrderStatus.setCreateTime(DateUtil.nowDateTime());
                        storeOrderStatuses.add(storeOrderStatus);
                        for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                            storeOrderInfo.setStatus(1);
                            e.setStatus(1);
                            if (Objects.equals(storeOrderInfo.getBuyer(), storeOrderInfo.getLecturer())) {
                                storeOrderInfo.setIsGet(true);
                            }
                            addOrderInfos.add(storeOrderInfo);
                        }
                        e.setStatus(1);
                    }
                    e.setTargetOrderId(targetOrderId);
                    //判断订单状态是否未支付 如果未支付 修改状态
                    e.setPaid(true);
                    e.setPayType("weixin");
                }
                //订单支付完成
                umsQueryResponse.setStatus(Boolean.TRUE);
                umsQueryResponse.setMsg("支付完成");
                payInfo.setBankType(params.get("bankInfo").toString());
                payInfo.setTimeEnd(payTime);
                payInfo.setTransactionId(targetOrderId);
                break;
            //订单转入退款流程
            case UmsPayConstants.UMS_PAY_STATUS_TRADE_REFUND:
                String refundAmount = params.get("refundAmount").toString();
                String refundOrderId = params.get("refundOrderId").toString();
                List<StoreOrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getUmsRefundOrderId, refundOrderId));
                //对礼品卡退款做处理
                //过滤出商品id
                List<Integer> productIds = orderInfoList.stream().filter(e -> e.getType().equals(4)).map(StoreOrderInfo::getProductId).collect(Collectors.toList());
                if (ObjectUtil.isNotEmpty(productIds)) {
                    //查询为礼品卡的商品
                    List<Integer> pIds = vcaProductService.list(
                            Wrappers.<VcaProduct>lambdaQuery()
                                    .in(VcaProduct::getId, productIds)
                                    .eq(VcaProduct::getCid, 750)
                    ).stream().map(VcaProduct::getId).collect(Collectors.toList());
                    if (ObjectUtil.isNotEmpty(pIds)) {
                        //取出礼品卡商品的子订单号
                        Map<Integer, StoreOrderInfo> productMap = VcaUtil.listToMap(orderInfoList, "productId", Integer.class);
                        List<String> o = pIds.stream().map(e -> productMap.get(e).getMerOrderNo()).collect(Collectors.toList());
                        //查询订单号对应的礼品卡并修改状态
                        List<UserCard> list = userCardService.list(Wrappers.<UserCard>lambdaQuery().in(UserCard::getOrderId, o));
                        list.forEach(e -> e.setStutus(2));
                        userCards.addAll(list);
                    }
                }
                orderInfos.addAll(orderInfoList);
                orderInfos.forEach(e -> {
                    //修改状态为 已退款
                    e.setRefundStatus(2);
                    //退款时间
                    e.setRefundReasonTime(DateUtil.nowDateTime());
                });
                List<String> orderNos = orderInfos.stream().map(StoreOrderInfo::getOrderNo).collect(Collectors.toList());
                orderList = orderList.stream().filter(e -> e.getOrderId().equals(orderNos.get(0))).collect(Collectors.toList());
                orderList.forEach(e -> {
                    e.setRefundStatus(2);
                    e.setRefundReasonTime(DateUtil.nowDateTime());
                    e.setRefundPrice(new BigDecimal(refundAmount).divide(new BigDecimal("100")).setScale(2, RoundingMode.UP));
                });
                for (StoreOrderInfo orderInfo : orderInfos) {
                    ids.add(orderInfo.getId());
                }
                log.info("订单------->{},退款成功", orderInfos.get(0).getOrderNo());
                //返回前端原因
                umsQueryResponse.setMsg("退款成功");
                //返回前端 true
                umsQueryResponse.setStatus(Boolean.TRUE);
                List<InvoiceOrderRelation> relations = invoiceOrderRelationService.list(Wrappers.<InvoiceOrderRelation>lambdaQuery().in(InvoiceOrderRelation::getOrderId, orderList.stream().map(StoreOrder::getId).collect(Collectors.toList())));
                if (ObjectUtil.isNotEmpty(relations)) {
                    redisUtil.lPush(TaskConstants.CREDIT_NOTE_LIST, JSON.parseArray(JSON.toJSONString(orderInfoList.stream().map(StoreOrderInfo::getMerOrderNo).collect(Collectors.toList()))).toString());
                }
                //判断订单退款状态
                break;
            default:
                thirdPartyExceptions = new ThirdPartyExceptions();
                thirdPartyExceptions.setErrcode(status);
                thirdPartyExceptions.setErrmsg(params.get("msgType").toString());
                thirdPartyExceptions.setData(JSON.toJSONString(params));
                thirdPartyExceptions.setRemark("银联全民付回调失败");
                thirdPartyExceptions.setType(2);
                break;
        }
        if (ObjectUtil.isEmpty(umsQueryResponse)) {
            return Boolean.FALSE;
        }
        logger.info("orderList----->{}", orderList);
        orders.addAll(orderList);

        ThirdPartyExceptions finalThirdPartyExceptions = thirdPartyExceptions;
        Boolean execute = transactionTemplate.execute(e -> {
            if (ObjectUtil.isNotEmpty(userCards)) {
                userCardService.updateBatchById(userCards);
            }
            if (ObjectUtil.isNotEmpty(finalThirdPartyExceptions)) {
                thirdPartyExceptionsService.save(finalThirdPartyExceptions);
            }
            if (orderInfos.size() > 0) {
                orderInfoService.updateBatchById(orderInfos);
            }
            if (addOrderInfos.size() > 0) {
                orderInfoService.updateBatchById(addOrderInfos);
                logger.info("orderInfos==>{}", orderInfos);
            }
            if (addUserCards.size() > 0) {
                userCardService.saveBatch(userCards);
            }
            if (status.equals(UmsPayConstants.UMS_PAY_STATUS_TRADE_REFUND)) {
                orders.forEach(g -> {
                    if (Boolean.TRUE.equals(orderService.getOrderInfoStatusIsAll(2, ids))) {
                        g.setRefundStatus(2);
                    }
                });
                StoreOrder storeOrder = orderService.getByOrderId(orderInfos.get(0).getOrderNo());
                storeOrderStatusService.createLog(storeOrder.getId(), Constants.ORDER_LOG_REFUND_APPLY, 1, "退款成功");
            }
            if (orders.size() > 0) {
                orderService.updateBatchById(orders);
                logger.info("orders----->{}", orders);
            }
            if (status.equals(UmsPayConstants.UMS_PAY_STATUS_TRADE_SUCCESS)) {
                // TODO: 2022/12/28 处理外部预约人数
                handlerAppoinent(addOrderInfos);
            }
            payInfoService.updateById(payInfo);
            return Boolean.TRUE;
        });
        //判断是否修改成功
        if (!execute) {
            umsQueryResponse.setMsg("退款失败");
            umsQueryResponse.setStatus(Boolean.FALSE);
            return Boolean.FALSE;
        }
        if (status.equals(UmsPayConstants.UMS_PAY_STATUS_TRADE_SUCCESS)) {
            orders.forEach(o -> {
                redisUtil.lPush(OrderRedisConstans.ORDER_PAY_SUCCESSFUL, o.getOrderId());
                redisUtil.lPush(OrderRedisConstans.ACTIVITY_START_KEY, o.getOrderId());
            });
        }
        logger.info("===================支付结果回调结束======================");
        return Boolean.TRUE;
    }

    /**
     * @param orders
     * @return 预下单返回对象
     * @Description 银联预下单
     * @Author: Li
     * @Data 2022/11/01 17:11
     */
    private Map<String, Object> unifiedorder(List<StoreOrder> orders, String openId) throws Exception {
        HashMap<String, String> info = systemConfigService.info(77);
        Map<String, String> umsPayConfig = getUmsPayConfig();
        //当前日期 格式为 yyyyMMddHHmmss
        String timestamp = DateUtil.nowDateTime(Constants.DATE_TIME_FORMAT_NUM);
        UmsPayVo umsPayVo = new UmsPayVo();

        //1. 组建请求报文
        List<String> expireTime = new ArrayList<>();
        orders.forEach(e -> {
            switch (e.getType()) {
                case 0:
                case 1:
                    expireTime.add(DateUtil.addDateSecond(e.getCreateTime(), Integer.parseInt(info.get(Constants.COURSE_CANCEL_TIME)) * 60));
                    break;
                case 2:
                    expireTime.add(DateUtil.addDateSecond(e.getCreateTime(), Integer.parseInt(info.get(Constants.TALK_CANCEL_TIME)) * 60));
                    break;
                case 3:
                    expireTime.add(DateUtil.addDateSecond(e.getCreateTime(), Integer.parseInt(info.get(Constants.EXHIBITION_CANCEL_TIME)) * 60));
                    break;
                case 4:
                    expireTime.add(DateUtil.addDateSecond(e.getCreateTime(), Integer.parseInt(info.get(Constants.ORDER_CANCEL_TIME)) * 60));
                    break;
                default:
                    expireTime.add(DateUtil.addDateSecond(e.getCreateTime(), 30 * 60));
                    break;
            }
        });
        umsPayVo.setExpireTime(expireTime.get(0));
        umsPayVo.setRequestTimestamp(timestamp);
        umsPayVo.setMid(umsPayConfig.get(UmsPayConstants.UMS_PAY_MID));
        umsPayVo.setTid(umsPayConfig.get(UmsPayConstants.UMS_PAY_TID));
        umsPayVo.setInstMid(UmsPayConstants.UMS_PAY_INSTMID_MINIDEFAULT);
        List<BigDecimal> payPrice = orders.stream().map(StoreOrder::getPayPrice).collect(Collectors.toList());
        List<BigDecimal> totalPrice = orders.stream().map(StoreOrder::getTotalPrice).collect(Collectors.toList());
        umsPayVo.setTotalAmount(payPrice.stream().reduce(BigDecimal.ZERO, BigDecimal::add).multiply(new BigDecimal("100")));
        umsPayVo.setMerOrderId(umsPayConfig.get(UmsPayConstants.UMS_SOURCE_NO) + timestamp + VcaUtil.randomCount(1000000, 9999999));
        umsPayVo.setOriginalAmount(totalPrice.stream().reduce(BigDecimal.ZERO, BigDecimal::add).multiply(new BigDecimal("100")));
        umsPayVo.setTradeType(UmsPayConstants.UMS_PAY_TRADETYPE_MINI);
        String notifyUrl = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_API_URL);
        umsPayVo.setNotifyUrl(notifyUrl);

        //2. 获取认证报文
        String authorization = umsUtils.getAccessToken();

        //3.根据 payType 选择支付链接
        String url = UmsPayUrlConstants.UMS_PAY_DEV_URL;
        url = url + UmsPayUrlConstants.UMS_PAY_WXPAY_URL;
        umsPayVo.setSubOpenId(openId);

        Map<String, String> headers = new HashMap();
        headers.put(UmsPayConstants.UMS_PAY_HEADER, authorization);
        //3. 发送http请求，并解析返回信息
        log.info("umsPayVo-------------------------------->{}", JSON.toJSONString(umsPayVo));
        String jsonData = restTemplateUtil.postMapData(url, JSON.parseObject(JSON.toJSONString(umsPayVo)), headers);
        JSONObject jsonObject = JSON.parseObject(jsonData);
        // 取出银联 全民付 错误码 进行判断是否下单成功
        log.info("jsonObject-------------------------------->{}", jsonObject);
        String errCode = jsonObject.getString("errCode");
        if ("1000".equals(errCode)) {
            redisUtil.delete(Constants.UMS_ACCESS_TOKEN);
            umsUtils.getAccessToken();
            throw new VcaException("下单失败");
        } else if (!errCode.equals(UmsPayConstants.UMS_PAY_ERRCODE_STATUS_SUCCESS)) {
            throw new VcaException("下单失败");
        }

        Map map = JSON.parseObject(jsonObject.toJSONString(), Map.class);
        //判断是否有 拉取微信支付参数
        if (ObjectUtil.isEmpty(map.get("miniPayRequest"))) {
            throw new VcaException("下单失败");
        }
        HashMap miniPayRequest = JSON.parseObject(map.get("miniPayRequest").toString(), HashMap.class);
        map.forEach((k, v) -> {
            if (!"miniPayRequest".equals(k)) {
                miniPayRequest.put(k, v.toString());
            }
        });
        String merOrderId = jsonObject.get("merOrderId").toString();
        orders.forEach(e -> {
            e.setUmsMerOrderId(merOrderId);
        });
        Boolean execute = false;
        execute = transactionTemplate.execute(e -> {
            orderService.updateBatchById(orders);
            return Boolean.TRUE;
        });
        if (!execute) {
            throw new VcaException("下单失败");
        }
        return miniPayRequest;
    }

}
